iT邦幫忙

2022 iThome 鐵人賽

DAY 10
0
Modern Web

Hello TypeScript 菜鳥系列 第 10

Day 9. TypeScript 參考型別:Enum

  • 分享至 

  • xImage
  •  

今天要討論的是Enum,Enum是個很有趣的東西,它是Object的一種變形,而Enum最重要的優點就是能提升程式碼的可讀性,所以接下來要好好來認識Enum,以後充分運用。


Enum是一群有關聯性、以可讀性比較高的一群常數值集合,這邊的常數值可以是number或string型別。

number型別常數值

以下先以常數值為number型別的範例來認識Enum:

enum Progress {
    NotStarted,
    InProgress,
    IsCompleted
}

假設現在希望用一種方式來表現工作的進度,進度分為三種:尚未開始(not started)、進行中(in process)、已完成(is completed),這裡我們先用enum型別來討論如何描述現在這樣的狀況。

Progress代表一項工作的進度,這裡一樣用NotStarted、InProgress、IsCompleted表示三種進度。而Enum型別預設會以NotStarted當作number型別常數值0的鍵值(key),接著InProgress和IsComplete自動依序代表number型別常數值1和2的鍵值,也就是說上面的例子就等同於:

enum Progress {
    NotStarted = 0,
    InProgress = 1,
    IsCompleted = 2
}

這是在沒有任何指定下的enum預設值。

當然也可以初始化第一個鍵值代表的常數值,接下來的常數就會依序自動給值,例如在用Enum表達月份的時候,可能會希望常數值和鍵值相呼應:

enum Mounth {
    January = 1,
    February,   // 2
    March,      // 3
    April,      // 4
    May,        // 5
    June,       // 6
    July,       // 7
    August,     // 8
    September,  // 9
    October,    // 10
    November,   // 11
    December    // 12

或者也可以自行給定每個鍵值所代表的初始值:

enum Quarter {
     Q1 = 0,
     Q2 = 25,
     Q3 = 50,
     Q4 = 75
}

String常數值

前面有提到常數值也可以是string型別,例如:

enum Mounth {

    January = "Jan",
    February = "Feb",   
    March = "Mar",  
    April = "Apr",
    May = "May", 
    June = "Jun", 
    July = "Jul",
    August = "Aug",
    September = "Sep",
    October = "Oct",
    November = "Nove",
    December = "Dec"

Enum的應用

Enum主要應用的情境如下:

  1. 需要使用非常多有相互關聯的常數變數們;
  2. 同時希望減少程式碼錯誤並提高可讀性。

回到Progess範例用一個極簡的例子來理解,假設這裡不使用Enum而是先單純以0、1、2來代表not started、not started、in progress、is completed、is completed三種開發任務的進度:

/*
    Progress
    0: not started
    1: in progress
    2: is completed
*/
let develop_tasks = {
    feature1: 2,
    feature2: 1,
    feature3: 0,
    feature4: 2,
}

function checkTaskProgress(feature){
    let progrss = ;
    switch(develop_task['feature']){
        case 0:
            progress = 'not started';
            break;
        case 1:     
            progress = 'in progress';
            break;
        case 2:     
            progress = 'is completed';
            break;
        default:
            return new Error('undefined value');
    };
    return progress
}

這一小段不太好的程式碼雖然在自己練習或是小型專案看似可行,但是當程式碼愈來愈多或專案愈來愈龐大,如果增加數值來表示其他種「進度」,開發到後期可能就會忘記這些數值的進度意義,而必須耗費時間去看註解或是文件等。

另外,未來若要修改數值所表示的進度,可能就變得比較難維護,因為除了要更動 checkTaskProgressswitch 回傳的進度,也需要修改原來develop_tasks 每個 feature*的進度數值,可能同時影響到其他有使用到這些進度數值的「工作」。

那如果精進一下程式碼,以一個物件 progress 表示進度和其數值:

const progress = {
    notStarted: 0,
    inProgress: 1,
    isCompleted: 2,
};

let develop_tasks = {
    feature1: progress.isCompleted,
    feature2: progress.inProgress,
    feature3: progress.notStarted,
    feature4: progress.isCompleted,
}

function checkTaskProgress(feature){
    switch(develop_task['feature']){
        case progress['notStarted']:
            return 'not started';
        case progress['inProgress']:
            return 'in progress';
        case progress['isCompleted']:     
            return 'is completed';
    };
    return new Error('undefined value');
}

這邊使用object型別已經改善最前面提到的幾個問題,但是要注意的是,object的 const 關鍵字不是指鍵值(key)和值(value)之間是常數關係,而是指 progress 這個object名字所參考到的物件是不可變動的,也因此稍有不慎, progress 鍵值的數值是可以被更改的。

這裡新增一個函式來確認一個任務是否尚未開始開發(not started),同時模擬不小心將 progress object的 notStarted 屬性值改成 -1(ˋ注意:這是可行的):

function isNotStarted(progress){
    if(!progress) return true;
    return false;
}

// ...
progress.notStarted = -1;    // ok


console.log(isNotStarted(feature3));    // false

因為 number 型別只有只有 0 才是falsy value,所以改成-1之後理所當然會回傳 false,而這樣的小錯誤可能就會導致程式碼後續會出現更多問題,所以 Enum 型別的常數值就能避免這樣的事情發生。

考慮到篇幅,以及為了加緊整個系列的腳步,今天只從一個菜鳥的角度簡單認識Enum的優點和應用,若想繼續深入Enum,可以官方文件搜尋Enum,或是參考TypeScript HandBook 的 Enum 章節


參考資料
TypeScript: JavaScript With Syntax For Types
TypeScript Tutorial
W3Schools Online Web Tutorials


上一篇
Day 8. TypeScript 參考型別:Tuple
下一篇
Day 10. TypeScript 參考型別:Union
系列文
Hello TypeScript 菜鳥31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言